#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "Logger.hpp"
#include "InetAddr.hpp"

const static int dsockfd = -1;
const static int gbacklog = 16;

enum
{
    SOCKET_CRATE_ERRO,
    SOCKET_BIND_ERRO,
    SOCKET_LISTEN_ERRO
};

class Socket
{
public:
    virtual ~Socket() {}
    virtual void CreateSocket() = 0;
    virtual void BindSocket(int port) = 0;
    virtual void ListenSocket(int backlog) = 0;
    virtual std::shared_ptr<TcpSocket> Accept(InetAddr*addr)=0;
    virtual int SockFd()=0;
    virtual void Close()=0;
    virtual ssize_t Recv(std::string*out)=0;
    virtual ssize_t Send(const std::string&in)=0;
public:
    void BuildSocket(int port)
    {
        CreateSocket();
        BindSocket(port);
        ListenSocket(gbacklog);
    }
};

class TcpSocket : public Socket
{
public:
    TcpSocket()
        : _sockfd(dsockfd)
    {
    }
    TcpSocket(int sockfd):_sockfd(sockfd)
    {}
    void CreateSocket() override
    {
        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd < 0)
        {
            LOG(LogLevel::FATAL) << "socket创建失败";
            exit(SOCKET_CRATE_ERRO);
        }
        LOG(LogLevel::INFO) << "socket创建成功,sockfd:" << _sockfd;
    }
    void BindSocket(int port) override
    {
        InetAddr local(port);
        if (bind(_sockfd, local.Addr(), local.lenth()) != 0)
        {
            LOG(LogLevel::FATAL) << "bind失败";
            exit(SOCKET_BIND_ERRO);
        }
        LOG(LogLevel::INFO) << "bind成功";
    }
    void ListenSocket(int backlog) override
    {
        if (listen(_sockfd, backlog) != 0)
        {
            LOG(LogLevel::FATAL) << "listen失败";
            exit(SOCKET_LISTEN_ERRO);
        }
        LOG(LogLevel::INFO) << "listen成功";
    }
    std::shared_ptr<TcpSocket> Accept(InetAddr*addr) override
    {
        struct sockaddr_in peer;
        socklen_t len=sizeof(peer);
        int fd=accept(_sockfd,(struct sockaddr*)&peer,&len);
        if(fd<0)
        {
            LOG(LogLevel::WARNING)<<"获取链接失败";
            return nullptr;
        }
        LOG(LogLevel::INFO)<<"获取链接成功,fd:"<<fd;
        addr->Init(peer);
        return std::make_shared<TcpSocket>(fd);
    }
    int SockFd() override
    {
        return _sockfd;
    }
    void Close() override
    {
        close(_sockfd);
    }
    ssize_t Recv(std::string*out) override
    {
        char buffer[1024];
        int n=recv(_sockfd,buffer,sizeof(buffer)-1,0);
        if(n>0)
        {
            buffer[n]=0;
            *out+=buffer;
        }
        return n;
    }

    ssize_t Send(const std::string&in)
    {
        return send(_sockfd,in.c_str(),in.size(),0);
    }
    ~TcpSocket() {}

private:
    int _sockfd;
};